iT邦幫忙

DAY 26
2

Javascript面面觀系列 第 26

Javascript面面觀:應用篇《V8》

  • 分享至 

  • xImage
  •  

V8算是很新的Javascript引擎,匆忙之間找到的應用不多...目前看到的其實都是在wikipedia上有提到的:

http://en.wikipedia.org/wiki/V8_(JavaScript_engine)
應用協助
http://code.google.com/p/cproxyv8/

http://code.google.com/p/v8-juice/

跟SpiderMonkey比較起來,V8要定義函數跟物件比較麻煩,cproxyv8使用一個proxy類別來包裝自訂的類別,這樣可以讓定義物件的方式比較簡單。

v8-juice也是類似的解決方案,不過他做了更進一步的擴充,包括一組plugin API及做type conversion的API,讓自訂及擴充更方便。

應用
* V8CGI

http://code.google.com/p/v8cgi/

這是一個底層使用V8引擎,整合FastCGI介面的應用,他包涵一個Apache module,透過這個方式,可以讓你用Javascript開發伺服器端的程式。除了使用V8 Javascript引擎,他也整合了一些重要的函式庫:

* I/O: File, Directory, Socket 等原生支援
* DB: MySQL, PostgreSQL, SQLite 等原生支援
* ActiveRecord, Query 等資料庫操作方法
* HTTP, Session, HTML 等協助類別
* Process 行程管理的原生支援
* Assertion, Template 等協助類別

使用V8
V8的主頁:http://code.google.com/p/v8/

V8的簡要開發文件:http://code.google.com/apis/v8/intro.html

V8也提供一個完整的API來使用。V8為了提昇速度,需要用比較麻煩的方式包裝,這樣可以讓他在GC等操作時有更好的效率,以及最終可以做到幾乎將Javascript程式與機器碼直接對應(據說)。

函數的使用比較簡單,他需要使用一個FunctionTemplate來包裝自訂的函數。物件的操作更麻煩,除了需要用ObjectTemplate來包裝,而且手續繁複,對於每個可以操作的屬性,都需要定義Accessor callback來操作,不過他也定義了一些可以進一步管理的函數,例如interceptor函數,可以對這些屬性操作做攔截。也因為使用比較麻煩,所以有像前面介紹的proxy類別這樣用來包裝自訂物件方法,提供統一的操作函數來避免需要大量自訂Accessor函數的狀況。

接下來就從V8的Sample範例中,想辦法拼出一個範例,目的是可以做到:
* 在Global加入一個print函數
* 在Global加入一個printFile函數
* 在Global加入一個自訂物件(結果有問題,以後再來嘗試好了。程式會在正常使用API的時候當掉...也許是版本及編譯器設定的問題...我使用Visual C++ 2008 Express)

然後透過參數傳入要執行的Javascript檔案名稱來執行,這幾個功能模仿之前的Rhino的例子,但是改成用C++搭配V8的API來實作。(全部放到主程式V8_001.cpp中,以程式組織來說這樣做不太好,但是可以運作...)

 #include "stdafx.h"
 
 using namespace v8;
 
 Handle<Value> Print(const Arguments& args);
 Handle<String> ReadFile(const char* name);
 Handle<Value> PrintFile(const Arguments& args);

 const char* ToCString(const String::Utf8Value& value) {
   return *value ? *value : "<string conversion failed>";
 }
 
 Handle<Value> Print(const Arguments& args) {
 	bool first = true;
 	for (int i = 0; i < args.Length(); i++) {
 		HandleScope handle_scope;
 		if (first) {
 			first = false;
 		} else {
 			printf(" ");
 		}
 		String::Utf8Value str(args[i]);
 		printf("%s", str);
 	}
 	printf("\n");
 	fflush(stdout);
 	return Undefined();
 }
 
 Handle<String> ReadFile(const char* name) {
 	FILE* file = fopen(name, "rb");
 	if (file == NULL) return Handle<String>();
 
 	fseek(file, 0, SEEK_END);
 	int size = ftell(file);
 	rewind(file);
 
 	char* chars = new char[size + 1];
 	chars[size] = '\0';
 	for (int i = 0; i < size;) {
 		int read = fread(&chars[i], 1, size - i, file);
 		i += read;
 	}
 	fclose(file);
 	Handle<String> result = String::New(chars, size);
 	delete[] chars;
 	return result;
 }
 
 Handle<Value> PrintFile(const Arguments& args) {
 	if (args.Length() ==1) {
 		String::Utf8Value str(args[0]);
 		Handle<String> result = ReadFile(ToCString(str));
 		String::AsciiValue rstr(result);
 		printf("%s", rstr);
 	}
 	printf("\n");
 	fflush(stdout);
 	return Undefined();
 }
 
 int main(int argc, char* argv[])
 {
 	if (argc<2) {
 		printf("Must provide a javascript file name.");
 		return 1;
 	}
 	
 	const char* str = argv[1];
 
 	HandleScope handle_scope;
 
 	Handle<ObjectTemplate> global = ObjectTemplate::New();
 	global->Set(String::New("print"), FunctionTemplate::New(Print));
 	global->Set(String::New("printFile"), FunctionTemplate::New(PrintFile));
 
 	Handle<Context> context = Context::New(NULL, global);
 
 	Context::Scope context_scope(context);
 
 	Handle<String> file_name = String::New(str);
 	Handle<String> source = ReadFile(str);
 	if (source.IsEmpty()) {
 		printf("Error reading '%s'\n", str);
 		V8::Dispose();
 		return 1;
 	}
 	Handle<Script> script = Script::Compile(source, file_name);
 	if (script.IsEmpty()) {
 		V8::Dispose();
 		return 1;
 	} else {
 		Handle<Value> result = script->Run();
 		if (result.IsEmpty()) {
 			V8::Dispose();
 			return 1;
 		} else {
 			if (!result->IsUndefined()) {
 				String::Utf8Value str(result);
 				printf("%s\n", str);
 			}
 		}
 	}
 	V8::Dispose();
 	return 0;
 }

(在stdafx.h裡面有一行:#include <v8.h>,另外要額外加入include及lib目錄指向V8裡面的include目錄及lib產生的目錄。)

測試用的Javascript檔案(test.js):

 function pyth(x,y) {
 	return sqrt(x*x+y*y);
 }
 function sqrt(x) {
 	return x*x;
 }
 print(pyth(2,3)+"\n");
 printFile('test.js');

測試結果會跑出:

 169
 
 function pyth(x,y) {
         return sqrt(x*x+y*y);
 }
 function sqrt(x) {
         return x*x;
 }
 print(pyth(2,3)+"\n");
 printFile('test.js');
 

結束,可惜目前只試出加入函數的方法...(不過我也試了半天而已就是了,應該早一點開始嘗試,這樣就不用趕截稿時間了。ReadFile、Print等函數其實是從Shell.cc裡面直接copy來用的,我只另外寫一個簡單的PrintFile。目前要print中文似乎有些問題,這也是要再研究的。)


上一篇
Javascript面面觀:應用篇《Rhino》
下一篇
Javascript面面觀:應用篇《JScript》
系列文
Javascript面面觀30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言